using GameFramework;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
using UnityGameFramework.Runtime;

namespace LS.Saving
{
    internal sealed partial class SavingManager
    {
        public sealed class SavingGroup: ISavingGroup
        {
            public const string m_DefaultExtension = ".lssave";

            private readonly string m_Name;
            private readonly string m_Folder;
            private readonly string m_Extension;
            private readonly LinkedList<IDataFile> m_SavingDataFiles;
            private ISavingHelper m_SavingHelper;
            private Database m_Database;
            private IDataFile m_LoadedFile;
            
            public string Name => m_Name;
            public string Folder => m_Folder;
            public string Extension => m_Extension;
            public int FileCount => m_SavingDataFiles.Count;

            public Database Database => m_Database;
            public IDataFile LoadedFile => m_LoadedFile;
            
            public SavingGroup(string name, string folder, string extension)
            {
                if (string.IsNullOrEmpty(extension))
                {
                    extension = m_DefaultExtension;
                }
                m_Name = name;
                m_Folder = folder;
                m_Extension = extension;
                m_SavingDataFiles = new LinkedList<IDataFile>();
                m_Database = new Database();
            }

            public void SetupHelper(ISavingHelper helper)
            {
                this.m_SavingHelper = helper;
            }

            public void Init()
            {
                if (m_SavingHelper == null)
                {
                    throw new Exception("Helper is null.");
                }
                string extension = m_Extension;
                if (string.IsNullOrEmpty(extension))
                {
                    extension = m_DefaultExtension;
                }
                m_SavingDataFiles.Clear();
                m_SavingHelper.GetAllFiles(Folder, $"*.{extension}", RefreshFile);
            }

            public IDataFile[] GetAllFile()
            {
                return m_SavingDataFiles
                    .OfType<IDataFile>()
                    .ToArray();
            }

            public IDataFile GetFile(string fileName)
            {
                return m_SavingDataFiles.First(d=>d.FileName == fileName);
            }

            public IDataFile GetRecentlyFile()
            {
                return m_SavingDataFiles.Last?.Value;
            }

            public IDataFile CreateFileInfo(string fileName)
            {
                return m_SavingHelper.CreateDataFile(Folder, fileName, Extension);
            }
            public bool Loaded(string fileName)
            {
                return LoadedFile != null && LoadedFile.FileName == fileName;
            }
            public bool Loaded()
            {
                return LoadedFile != null;
            }
            
            public bool HasFile(string fileName)
            {
                return m_SavingDataFiles.Any(d=> d.FileName == fileName || d.FullPath == fileName);
            }

            public void LoadFile(Action<bool, string> resultAction)
            {
                IDataFile file = GetRecentlyFile();
                LoadFile(file, resultAction);
            }

            public void LoadFile(IDataFile file, Action<bool, string> resultAction)
            {
                if (file == null)
                {
                    resultAction(false, "No file found.");
                    return;
                }

                if (!file.Existed)
                {
                    resultAction(false, $"File with path {file.FullPath} not existed.");
                    return;
                }
                
                m_LoadedFile  = file;
                Database.Clear();
                m_SavingHelper.LoadFile(file, Database, resultAction);
            }

            public void SaveFile(Action<bool, string> resultAction)
            {
                IDataFile file = GetRecentlyFile();
                SaveFile(file, resultAction);
            }

            public void SaveFile(IDataFile file, Action<bool, string> resultAction)
            {
                var fileInfo = this.m_SavingDataFiles.Find(file).Value;
                if (fileInfo == null)
                {
                    m_SavingDataFiles.AddLast(fileInfo);
                }
                else
                {
                    m_LoadedFile = fileInfo;
                    m_SavingDataFiles.Remove(fileInfo);
                    m_SavingDataFiles.AddLast(fileInfo);
                }
                m_SavingHelper.SaveFile(file, Database, resultAction);
            }

            public void DeleteFile()
            {
                if (LoadedFile != null)
                {
                    m_LoadedFile = null;
                    m_SavingHelper.DeleteFile(LoadedFile);
                }
            }

            public void DeleteFile(IDataFile file)
            {
                m_SavingHelper.DeleteFile(file);
            }

            public void ClearLoaded()
            {
                m_LoadedFile = null;
                m_Database.Clear();
                m_Database.ClearDirty();
            }

            private void RefreshFile(IDataFile[] files)
            {
                m_SavingDataFiles.Clear();
                foreach (IDataFile file in files)
                {
                    m_SavingDataFiles.AddLast(file);
                }
                SortFileWithTimestamp();
            }
            
            private void SortFileWithTimestamp()
            {
                var fileList = m_SavingDataFiles.ToList();
                fileList.Sort((a, b) => a.Timestamp.CompareTo(b.Timestamp));
                m_SavingDataFiles.Clear();
                foreach (var item in fileList)
                {
                    m_SavingDataFiles.AddLast(item);
                }
            }
        }
    }
}
